package net.sudot.chess.business.service;

import net.sudot.chess.business.dao.UserDao;
import net.sudot.chess.business.model.User;
import net.sudot.chess.config.SystemProperties;
import net.sudot.chess.exception.BusinessException;
import net.sudot.commons.pagination.Page;
import net.sudot.commons.pagination.Pageable;
import net.sudot.commons.security.event.UserLoggedInEvent;
import net.sudot.commons.security.event.UserLoggedOutEvent;
import net.sudot.commons.security.event.UserRegisteredEvent;
import net.sudot.commons.utils.Pbkdf2PasswordEncoder;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.DisabledAccountException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.pam.UnsupportedTokenException;
import org.apache.shiro.subject.Subject;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.HashSet;

/**
 * 用户管理
 *
 * @author tangjialin on 2018-03-30.
 */
@Service
public class UserService extends BaseService<User> {
    @Resource
    private SystemProperties systemProperties;
    @Resource
    private ApplicationEventPublisher applicationEventPublisher;
    @Resource
    private UserDao userDao;

    /**
     * 分页查询用户信息
     *
     * @param page 分页信息
     * @return 返回查询结果
     */
    public Page<User> findList(Pageable page) {
        return userDao.findList(page);
    }

    /**
     * 通过用户名获取用户信息
     *
     * @param username 账号
     * @return 不存在返回null
     */
    public User findByUsername(String username) {
        return userDao.findByUsername(username);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public User save(User user) {
        String username = user.getUsername();
        User existUser = username == null || username.isEmpty() ? null : findByUsername(username);
        if (existUser != null) { throw new BusinessException("用户名已存在"); }
        user.setEnabled(true);
        user.setLocked(false);
        user.setPassword(Pbkdf2PasswordEncoder.createHash(systemProperties.getDefaultPassword()));
        return super.save(user);
    }

    @Override
    public User saveOrUpdate(User user) {
        if (user.getId() == null) {
            user = save(user);
        } else {
            HashSet<String> ignoreProperties = new HashSet<>();
            ignoreProperties.add("enabled");
            ignoreProperties.add("locked");
            ignoreProperties.add("lockDate");
            ignoreProperties.add("lastLoginIp");
            ignoreProperties.add("lastLoginDate");
            user = update(user, ignoreProperties);
        }
        return user;
    }

    @Transactional(rollbackFor = Exception.class)
    public void register(User user) {
        save(user);
        applicationEventPublisher.publishEvent(new UserRegisteredEvent(this, user));
    }

    /**
     * 用户登录
     *
     * @param authenticationToken 登录令牌
     * @return 返回登录结果
     */
    public void login(AuthenticationToken authenticationToken) {
        try {
            Subject subject = SecurityUtils.getSubject();
            subject.login(authenticationToken);
            applicationEventPublisher.publishEvent(new UserLoggedInEvent(this, (User) subject.getPrincipal()));
        } catch (UnknownAccountException | IncorrectCredentialsException e) {
            throw new BusinessException("账号或密码错误", e);
        } catch (LockedAccountException e) {
            throw new BusinessException("账号已锁定", e);
        } catch (DisabledAccountException e) {
            throw new BusinessException("账号已禁用", e);
        } catch (UnsupportedTokenException e) {
            throw new BusinessException("不支持的登录类型", e);
        } catch (AuthenticationException e) {
            throw new BusinessException("登陆失败", e);
        }
    }

    /**
     * 用户登出
     */
    public void logout() {
        Subject subject = SecurityUtils.getSubject();
        applicationEventPublisher.publishEvent(new UserLoggedOutEvent(this, (User) subject.getPrincipal()));
        subject.logout();
    }

    @Transactional(rollbackFor = Exception.class)
    public User authentication(AuthenticationToken authenticationToken) {
        if (authenticationToken == null) { throw new NullPointerException(); }
        User user = null;
//        if (authenticationToken instanceof SocialUserAuthenticationToken) {
//            SocialUserAuthenticationToken token = (SocialUserAuthenticationToken) authenticationToken;
//            SocialUser socialUser = token.getSocialUser();
//            user = socialUser == null || socialUser.getUserId() == null ? null : find(socialUser.getUserId());
//            if (user == null) { throw new UnknownAccountException(); }
//        } else if (authenticationToken instanceof UserAuthenticationToken) {
//            UserAuthenticationToken token = (UserAuthenticationToken) authenticationToken;
//            Object principal = authenticationToken.getPrincipal();
//            if (token.getUserClass() == Admin.class) {
//                if (principal == null || String.valueOf(principal).isEmpty()) {
//                    throw new BusinessException("请输入有效的用户名");
//                }
//            } else {
//                if (principal == null || !ObjectUtil.isMobile(String.valueOf(principal))) {
//                    throw new BusinessException("请输入有效的手机号码");
//                }
//            }
//            Class<?> userClass = token.getUserClass();
//            Object credentials = authenticationToken.getCredentials();
//            String password = credentials == null ? null : (credentials instanceof char[] ? new String((char[]) credentials) : credentials.toString());
//            if (password == null || password.isEmpty()) { throw new BusinessException("请输入有效的登录密码"); }
//
//            UserProvider userProvider = getUserProvider(userClass);
//            user = userProvider != null ? (User) userProvider.getUser(principal) : null;
//            if (user == null) { throw new UnknownAccountException(); }
//            if (token.isVerifyCredentials()) {
//                boolean validatePassword = user.getPassword() != null;
//                try {
//                    validatePassword = validatePassword && Pbkdf2PasswordEncoder.validatePassword(password, user.getPassword());
//                } catch (Exception e) {
//                    throw new IncorrectCredentialsException();
//                }
//                if (!validatePassword) {
//                    getFailedLoginAttempts(user);
//                    tryLock(user);
//                    throw new IncorrectCredentialsException();
//                }
//            }
//        } else if (authenticationToken instanceof JwtUserAuthenticationToken) {
//            JwtUserAuthenticationToken token = (JwtUserAuthenticationToken) authenticationToken;
//            Jwt.Payload payload = Jwt.verify((String) token.getPrincipal(), systemProperties.getJwtSecret());
//            if (payload == null) { throw new BusinessException("无效的身份凭证"); }
//            UserProvider userProvider = getUserProvider(token.getUserClass());
//            user = userProvider != null ? (User) userProvider.getUser(payload.getSub()) : null;
//            if (user == null) { throw new UnknownAccountException(); }
//        }
//        Boolean locked = user.getLocked();
//        if (locked != null && locked) { throw new LockedAccountException(); }
//        Boolean enabled = user.getEnabled();
//        if (enabled != null && !enabled) { throw new DisabledAccountException(); }
//
//        user.setLastLoginDate(Instant.now());
//        user.setLastLoginIp(((UsernamePasswordToken) authenticationToken).getHost());
//        update(user);
        return user;
    }

}
